home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Tools / ResAnomaly 1.2 ƒ / ResAnomaly Source / FrDropApp.cp next >
Text File  |  1995-08-04  |  10KB  |  432 lines

  1.  
  2. // * This is ResAnomaly.        Based on FrDropApp
  3. // * ©1995 Chris K. Thomas.        ©1994 Metrowerks Inc. All Rights Reserved.
  4.  
  5. /*
  6.     ckt July the Second 1995
  7.     
  8.     Grab text resources up front to support the current architecture of
  9.     ResAnomaly. Eventually, I think we're going to go to three stages:
  10.     
  11.         …resource file is open
  12.     Stage One:      Data retrieval.  Gather all the named resources
  13.                     in the file into a list.
  14.         …resource file is closed
  15.     
  16.     Stage Two:      Analysis.  Check to be sure
  17.                     there aren't duplicate names & other stuff
  18.     
  19.     Stage Three:    Emitter.  Write the data in the proper format
  20.                     to the output stream.
  21.     
  22.     Currently, we only effectively have a mixed version of stages 1 & 3,
  23.     and the resource file is open throughout, which makes it difficult
  24.     to get to our own resources without abusing the Resource Mangler.
  25. */
  26.  
  27. #define DEBUG_ME Yes, Please
  28. //#define COMPILERS_GOT_BOOL Yup
  29.  
  30. #if  (defined DEBUG_ME) && (defined __powerc)
  31. #pragma traceback on
  32. #endif
  33.  
  34. // ————• Us
  35. #include "FrDropApp.h"
  36. #include "SpinCursorLib.h"
  37. //#include <ctype.h>  // why isn't isspace() inline???????????????
  38.  
  39. #ifndef COMPILERS_GOT_BOOL
  40. #define bool Boolean
  41. #endif
  42.  
  43. // * rewriting ANSI C library to circumvent inclusion of
  44. // * the whole library is annoying!
  45.  
  46. // * is whitespace?
  47. inline bool isspace(char inIs)
  48. {
  49.     bool out = false;
  50.     
  51.     if(inIs == ' ' || inIs == '\t')
  52.     {
  53.         out = true;
  54.     }
  55.     
  56.     return out;
  57. }
  58.  
  59. // * is AlphaNumeric?
  60. inline bool isalphanum(char inIs)
  61. {
  62.     bool out = false;
  63.     
  64.     if(        (inIs >= 'a' && inIs <= 'z')
  65.         ||    (inIs >= 'A' && inIs <= 'Z')
  66.         ||    (inIs >= '0' && inIs <= '9'))
  67.     {
  68.         out = true;
  69.     }
  70.     
  71.     return out;
  72. }
  73.  
  74. // ————• PP
  75. #include <UException.h>
  76. #include <LModelDirector.h>
  77. #include <LFileStream.h>
  78. #include <UAppleEventsMgr.h>
  79. #include <LHandleStream.h>
  80. #include <UMemoryMgr.h>
  81.  
  82. // ————• my less annoying (to the programmer) standard file replacement
  83. #include "StFile.h"
  84.  
  85. const ResIDT    ALRT_NoFiles    = 200;
  86.  
  87. static void InsertTextIntoStream(Handle inOurResource, LStream &inStream);
  88. static void InsertTextIntoStream(short inID, LStream &inStream);
  89. static void AddDotExtension(Str255 ioString, const Str255 inDot);
  90.  
  91. // ===========================================================================
  92. //        • Main Program
  93. // ===========================================================================
  94.  
  95. void main(void)
  96. {
  97.     try
  98.     {
  99.         FrDropApp    gApp;
  100.         gApp.Run();
  101.     }
  102.     catch(...)
  103.     {
  104.         ParamText("\pResAnomaly: I don't understand why, but I can't finish the task.", "\p", "\p", "\p");
  105.         StopAlert(129, NULL);
  106.     }
  107. }
  108.  
  109.  
  110. // ===========================================================================
  111. //        • FrDropApp Class
  112. // ===========================================================================
  113.  
  114. FrDropApp::FrDropApp()
  115. {
  116.     MaxApplZone();
  117.  
  118.     InitGraf((Ptr) &qd.thePort);        // Toolbox Managers
  119.     InitFonts();
  120.     InitWindows();
  121.     InitMenus();
  122.     TEInit();
  123.     InitDialogs(nil);
  124.     
  125.     new LModelDirector(this);            // AppleEvent Handlers
  126.     
  127.     mRunning = true;
  128.     
  129.     // * preload our text, because we can't access
  130.     // * our res file during processing
  131.     
  132.     mTextBeginLine = Get1Resource('TEXT', 128);
  133.     mTextIDequals = Get1Resource('TEXT', 130);
  134.     mTextIDend = Get1Resource('TEXT', 131);
  135.     mOutputHeaderStart = Get1Resource('TEXT', 256);
  136.     mOutputHeaderStop = Get1Resource('TEXT', 257);
  137.     
  138.     ThrowIfNULL_(mTextBeginLine);
  139.     ThrowIfNULL_(mTextIDequals);
  140.     ThrowIfNULL_(mTextIDend);
  141.     ThrowIfNULL_(mOutputHeaderStart);
  142.     ThrowIfNULL_(mOutputHeaderStop);
  143.     
  144.     ReadPrefs();
  145. }
  146.  
  147.  
  148. void
  149. FrDropApp::ReadPrefs()
  150. {
  151.     FSSpec    ourSpec;
  152.     
  153.     FSMakeFSSpec(0, 0, "\pPrefs.rsrc", &ourSpec);
  154.     LFile    prefsFile(ourSpec);
  155.     prefsFile.OpenResourceFork(fsRdPerm);
  156.     
  157.     ResAnomalyPrefs    **ourPrefs = (ResAnomalyPrefs **)GetResource('®prf', 128);
  158.     ThrowIfNULL_(ourPrefs);
  159.     
  160.     BlockMoveData(*ourPrefs, &mCurrentPrefs, sizeof(ResAnomalyPrefs));
  161.     
  162.     ReleaseResource((Handle)ourPrefs);
  163.     prefsFile.CloseResourceFork();
  164. }
  165.  
  166.  
  167. void
  168. FrDropApp::Run()
  169. {
  170.         // This program has no user interface. We only care
  171.         // about AppleEvents.
  172.         
  173.     while (mRunning) {
  174.         EventRecord        macEvent;
  175.         if (WaitNextEvent(everyEvent, &macEvent, 2, nil)) {
  176.         
  177.             if (macEvent.what == kHighLevelEvent) {
  178.                 AEProcessAppleEvent(&macEvent);
  179.             }
  180.         }
  181.     }
  182. }
  183.  
  184.  
  185. void
  186. FrDropApp::HandleAppleEvent(
  187.     const AppleEvent    &inAppleEvent,
  188.     AppleEvent            &outAEReply,
  189.     AEDesc                &outResult,
  190.     long                inAENumber)
  191. {
  192.     switch (inAENumber) {
  193.     
  194.         case ae_OpenApp:
  195.             StartUp();
  196.             break;
  197.             
  198.         case ae_OpenDoc:
  199.             DoAEOpenDoc(inAppleEvent, outAEReply, inAENumber);
  200.             break;
  201.             
  202.         case ae_Quit:
  203.             DoQuit();
  204.             break;
  205.             
  206.         default:
  207.             LModelObject::HandleAppleEvent(inAppleEvent, outAEReply, outResult, inAENumber);
  208.             break;
  209.     }
  210. }
  211.  
  212.  
  213. void
  214. FrDropApp::StartUp()
  215. {
  216.         // User double-clicked on the Program's icon
  217.         
  218.         // This program only works when files are dragged on the
  219.         // program's icon in the Finder. So we just display an
  220.         // Alert (which could have instructions for using the program)
  221.         // and then quit.
  222.     
  223.     ::Alert(ALRT_NoFiles, nil);
  224.     DoQuit();
  225. }
  226.  
  227.  
  228. void
  229. FrDropApp::DoAEOpenDoc(
  230.     const AppleEvent    &inAppleEvent,
  231.     AppleEvent&            /*outAEReply*/,
  232.     long                /*inAENumber*/)
  233. {
  234.     AEDescList    docList;
  235.     OSErr        err = AEGetParamDesc(&inAppleEvent, keyDirectObject,
  236.                             typeWildCard, &docList);
  237.     if (err != noErr) Throw_(err);
  238.     
  239.     Int32    numDocs;
  240.     err = AECountItems(&docList, &numDocs);
  241.     if (err != noErr) Throw_(err);
  242.     
  243.         // Loop through all items in the list
  244.             // Extract descriptor for the document
  245.             // Coerce descriptor data into a FSSpec
  246.             // Tell Program object to open document
  247.         
  248.     for (Int32 i = 1; i <= numDocs; i++) {
  249.         AEKeyword    theKey;
  250.         DescType    theType;
  251.         FSSpec        theFileSpec;
  252.         Size        theSize;
  253.         err = AEGetNthPtr(&docList, i, typeFSS, &theKey, &theType,
  254.                             (Ptr) &theFileSpec, sizeof(FSSpec), &theSize);
  255.         if (err != noErr) Throw_(err);
  256.         OpenDocument(&theFileSpec);
  257.     }
  258.     
  259.     AEDisposeDesc(&docList);
  260.     
  261.     DoQuit();
  262. }
  263.  
  264.  
  265. void
  266. FrDropApp::OpenDocument(
  267.     FSSpec    *inMacFSSpec)
  268. {
  269.     FSSpec            saveSpec = *inMacFSSpec;
  270.     Handle            curRes;
  271.     long            numTypes;
  272.     long            numRes;
  273.     long            i, j;
  274.     short            currentID;
  275.     ResType            currentType;
  276.     Str255            currentName;
  277.     Str255            numString;
  278.     LHandleStream    ourStream;
  279.     CursorSet        busyCursor(256, 4);
  280.     
  281.     InsertTextIntoStream(mOutputHeaderStart, ourStream);
  282.     ourStream.WriteData(&inMacFSSpec->name[1], inMacFSSpec->name[0]);
  283.     InsertTextIntoStream(mOutputHeaderStop, ourStream);
  284.     
  285.     Try_{
  286.         LFile            resFile(*inMacFSSpec);
  287.  
  288.         SetResLoad(false);
  289.         resFile.OpenResourceFork(fsRdPerm);
  290.         SetResLoad(true);
  291.         
  292.         numTypes = Count1Types();
  293.         
  294.         for(i = 1; i <= numTypes; i++)
  295.         {
  296.             Get1IndType(¤tType, i);
  297.             ThrowIfResError_();
  298.             
  299.             numRes = Count1Resources(currentType);
  300.             ThrowIfResError_();
  301.             
  302.             for(j = 1; j <= numRes; j++)
  303.             {
  304.                 busyCursor.Spin();
  305.             
  306.                 SetResLoad(false);
  307.                 curRes = Get1IndResource(currentType, j);
  308.                 SetResLoad(true);
  309.                 
  310.                 ThrowIfResError_();
  311.                 ThrowIfNULL_(curRes);
  312.                 
  313.                 GetResInfo(curRes, ¤tID, NULL, currentName);
  314.                 ThrowIfResError_();
  315.                 
  316.                 // * if the resource isn't named, how does one identify it?
  317.                 if(currentName[0] > 0)
  318.                 {
  319.                     MapToValidC(currentName);    //convert name to C-language usable
  320.                     
  321.                     // * Write a type string in the format const short kResNameType = 'type';
  322.                     
  323.     //                    InsertTextIntoStream(128, ourStream);    // "const kResource"
  324.     //                    ourStream.WriteData(¤tName[1], currentName[0]); // "<name>"
  325.     //                    InsertTextIntoStream(129, ourStream);    // "Type = '"
  326.     //                    ourStream.WriteData(¤tType, sizeof(ResType)); // "tnam"
  327.     //                    InsertTextIntoStream(131, ourStream);    // "';\r"
  328.                     
  329.                     // * Write an ID string in the format const short kResNameID = id#;
  330.                     InsertTextIntoStream(mTextBeginLine, ourStream);    // "const kResource"
  331.                     ourStream.WriteData(¤tName[1], currentName[0]); // "<name>"
  332.                     ourStream.WriteData(¤tType, sizeof(ResType));    //tnam
  333.                     InsertTextIntoStream(mTextIDequals, ourStream);    // "ID = '"
  334.                     NumToString(currentID, numString);
  335.                     ourStream.WriteData(&numString[1], numString[0]);
  336.                     InsertTextIntoStream(mTextIDend, ourStream);    // "';\r"
  337.                 }
  338.                 
  339.                 ReleaseResource(curRes);
  340.             }
  341.         }
  342.  
  343.         resFile.CloseResourceFork();
  344.         
  345.         // * we can now safely access our own resources
  346.         
  347.         AddDotExtension(inMacFSSpec->name, mCurrentPrefs.rapDotExtension);
  348.     
  349.         StPutFile    newFile("\pSave Resource Constants as:", *inMacFSSpec);
  350.         
  351.         if(newFile.reply.sfGood)
  352.         {
  353.             LFile        ourFile(newFile.reply.sfFile);
  354.             
  355.             if(newFile.reply.sfReplacing)
  356.                 ThrowIfOSErr_(FSpDelete(&newFile.reply.sfFile));
  357.             
  358.             ourFile.CreateNewDataFile(mCurrentPrefs.rapCreator, 'TEXT');
  359.             
  360.             StHandleLocker stlock(ourStream.GetDataHandle());
  361.             
  362.             ourFile.OpenDataFork(fsWrPerm);
  363.             ourFile.WriteDataFork(*ourStream.GetDataHandle(), ourStream.GetLength());
  364.             ourFile.CloseDataFork();
  365.         }
  366.     }
  367.     Catch_(inErr)
  368.     {
  369.         Str255 str;
  370.         
  371.         NumToString(inErr,str);
  372.         ParamText(inMacFSSpec->name, str, "\p", "\p");
  373.         CautionAlert(129, NULL);
  374.     } EndCatch_
  375. }
  376.  
  377. // * add a .dot extension to a Mac filename (yuk!)
  378. // * this would make a good alternate constructor argument for
  379. // * StPutFile.
  380. void AddDotExtension(Str255 ioString, const Str255 inDot)
  381. {
  382.     if(ioString[0] >= 32 - inDot[0]) //make space if necessary
  383.         ioString[0] -= inDot[0];
  384.     
  385.     BlockMoveData(&inDot[1], &ioString[ioString[0] + 1], inDot[0]);
  386.     ioString[0] +=inDot[0];
  387.     // * yeah, I know that can be optimized
  388. }
  389.  
  390. // * map a string to valid C chars only.
  391. void FrDropApp::MapToValidC(Str255 ioString)
  392. {
  393.     for(long i = 1; i <= ioString[0]; i++)
  394.     {
  395.         if(isspace(ioString[i]))    //whitespace
  396.         {
  397.             ioString[i] = mCurrentPrefs.rapReplaceWhitespace;
  398.         }
  399.         else if(!isalphanum(ioString[i])) //english characters or numbers
  400.         {
  401.             ioString[i] = mCurrentPrefs.rapReplaceNonAlphaNumeric;
  402.         }
  403.     }
  404. }
  405.  
  406. void InsertTextIntoStream(Handle inOurResource, LStream &inStream)
  407. {
  408.     ThrowIfNULL_(inOurResource);
  409.     
  410.     StHandleLocker    stlock(inOurResource);
  411.     inStream.WriteData(*inOurResource, GetHandleSize(inOurResource));
  412. }
  413.  
  414.  
  415. // * insert contents of a 'TEXT' resource into an LStream
  416. void InsertTextIntoStream(short inID, LStream &inStream)
  417. {
  418.     Handle ourResource = Get1Resource('TEXT', inID);
  419.     
  420.     InsertTextIntoStream(ourResource, inStream);
  421.     
  422. //    purposely don't dispose text - res manager serves as cache mechanism
  423. //    not an efficient one, to be sure, but it works.
  424. // * * * can't use this safely when other res forks are open unless
  425. // * * * guarantee our home currency
  426. }
  427.  
  428. void
  429. FrDropApp::DoQuit()
  430. {
  431.     mRunning = false;
  432. }